package com.bzkj.document.service.finishedproductentry.impl;

import com.bzkj.common.constant.BillStatusConstant;
import com.bzkj.common.core.domain.AjaxResult;
import com.bzkj.common.core.domain.model.LoginUser;
import com.bzkj.common.domain.NccApiResponse;
import com.bzkj.common.enums.BusinessType;
import com.bzkj.common.enums.DocumentType;
import com.bzkj.common.utils.DataProcessCommonUtils;
import com.bzkj.common.utils.MessageUtil;
import com.bzkj.common.utils.http.NccHttpUtils;
import com.bzkj.document.domain.finishedproduct.vo.FinishedProductBodyVo;
import com.bzkj.document.domain.finishedproduct.vo.FinishedProductHeadVo;
import com.bzkj.document.enums.InventoryCheck;
import com.bzkj.document.exception.InventoryException;
import com.bzkj.document.mapper.FinishedProductInMapper;
import com.bzkj.document.service.finishedproductentry.FinishedProductEntryService;
import com.bzkj.document.service.finishedproductentry.FinishedProductInService;
import com.bzkj.document.utils.common.DataProcessUtils;
import com.bzkj.document.utils.common.InventoryManagerUtils;
import com.bzkj.document.utils.finishedProductin.FinishProductInUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;

/**
 * @projectName: bzkj-wms
 * @package: com.bzkj.document.service.finishedproductentry.impl
 * @className: FinishedProductInServiceImpl
 * @description: 产成品入库单服务实现类
 * @author: C1309
 * @createDate: 2024年11月28日
 * @version: v1.0
 */
@Service
public class FinishedProductInServiceImpl implements FinishedProductInService {

    /**
     * 产成品入库单Mapper
     */
    @Resource
    private FinishedProductInMapper finishedProductInMapper;

    /**
     * NCC请求工具类
     */
    @Resource
    private NccHttpUtils nccHttpUtils;

    @Resource
    private FinishedProductEntryService finishedProductEntryService;

    /**
     * wms库存管理模块
     */
    @Resource
    private InventoryManagerUtils inventoryManagerUtils;

    /**
     * 单据解析工具类
     */
    @Resource
    private FinishProductInUtils finishProductInUtils;

    /**
     * 消息工具类
     */
    @Resource
    private MessageUtil messageUtil;

    /**
     * 产成品入库单签字
     */
    private static final String PRODUCTION_SIGN_API_URL = "/nccloud/api/ic/productin/sign";

    /**
     * 产成品入库单删除
     */
    private static final String PRODUCTION_DELETE_API_URL = "/nccloud/api/ic/productin/delete";

    /**
     * 产成品入库单更新
     */
    private static final String NCC_UPDATE_URL = "/nccloud/api/ic/productin/update"; // NCC更新接口URL
    // ==========================================================
    // 模块名称: NCC产成品入库单签字模块
    // 功能描述: 对NCC产成品入库单签字操作
    // ==========================================================

    /**
     * 产成品入库单签字
     *
     * @param cgeneralhid 表头
     * @param loginUser   用户信息
     * @return 结果
     */
    @Override
    public AjaxResult finishedProductInSignature(String cgeneralhid, LoginUser loginUser) {
        // 参数校验：请求参数是否为空，headerId是否存在
        if (cgeneralhid == null || cgeneralhid.isEmpty()) {
            return AjaxResult.error(messageUtil.noSelectOrderMessage(DocumentType.FINISHED_PRODUCT_INBOUND.getCode(), "签字"));
        }
        // 获取当前单据状态
        HashMap<String, String> billStatusMap = finishedProductInMapper.getBillStatus(cgeneralhid);
        String billStatus = billStatusMap.get("billState");
        String vbillcode = billStatusMap.get("vbillcode");
        // 根据单据状态返回消息
        AjaxResult ajaxResult = messageUtil.signedBillMessage(billStatus, DocumentType.FINISHED_PRODUCT_INBOUND.getDescription());
        return ajaxResult.isSuccess() ? processSignBill(cgeneralhid, vbillcode, loginUser) : ajaxResult;
    }

    /**
     * 对已完成的单据进行签字处理
     *
     * @param cgeneralhid 表头主键
     * @param vBillCode   单据编号
     * @param loginUser   登录用户
     * @return 结果
     */
    private AjaxResult processSignBill(String cgeneralhid, String vBillCode, LoginUser loginUser) {
        try {
            // 准备表头数据
            HashMap<String, Object> headerMap = prepareHeaderData(cgeneralhid);
            String vtrantypecode = headerMap.get("vtrantypecode").toString();

            // 校验并准备明细数据
            List<HashMap<String, Object>> detailList = prepareDetails(cgeneralhid, vtrantypecode);

            if (detailList.isEmpty()) {
                return AjaxResult.error(messageUtil.updateDocumentZeroQuantityMessage(DocumentType.FINISHED_PRODUCT_INBOUND.getCode()));
            }

            // 更新产成品入库单
            AjaxResult updateResult = updateFinishedInOrder(headerMap, detailList, loginUser);
            if (!updateResult.isSuccess()) {
                return updateResult;
            }

            // 调用外部接口并更新状态
            return handleExternalApiAndInventory(cgeneralhid, vBillCode, loginUser, detailList.size());
        } catch (Exception e) {
//            logError("采购入库单签字异常", e); // 记录异常日志
            String exceptionMessage = messageUtil.operateExceptionMessage(DocumentType.FINISHED_PRODUCT_INBOUND.getCode(), e, "签字");
            throw new RuntimeException(exceptionMessage, e);
        }
    }

    /**
     * 校验并准备明细数据
     *
     * @param cgeneralhid 单据表头主键
     * @return 明细列表或null（校验失败）
     */
    private List<HashMap<String, Object>> prepareDetails(String cgeneralhid, String vtrantypecode) {
        // 查询单据明细信息
        List<FinishedProductBodyVo> details = finishedProductInMapper.selectFinishedProductDetails(cgeneralhid, null);
        // 构建更新明细列表
        List<HashMap<String, Object>> detailList = new ArrayList<>();
        // 校验库存是否充足
        boolean verifiedInventorySign = inventoryManagerUtils.verifyInventorySign(details, "warehousein", vtrantypecode, DocumentType.FINISHED_PRODUCT_INBOUND.getCode());
        if (verifiedInventorySign) {
            for (FinishedProductBodyVo detail : details) {

                HashMap<String, Object> detailMap = new HashMap<>();
                detailMap.put("cgeneralbid", detail.getCgeneralbid());
                detailMap.put("nnum", detail.getNnum());
                detailList.add(detailMap);
            }
        }
        return detailList;
    }

    /**
     * 准备表头数据
     *
     * @param cgeneralhid 单据编号
     * @return 表头数据
     */
    private HashMap<String, Object> prepareHeaderData(String cgeneralhid) {
        FinishedProductHeadVo finishedProductHeadVo = finishedProductInMapper.selectFinishedInHeaderByBillCode(cgeneralhid);
        if (finishedProductHeadVo == null) {
            throw new IllegalStateException("产成品入库单表头信息不存在！");
        }

        HashMap<String, Object> headerMap = new HashMap<>();
        headerMap.put("cgeneralhid", finishedProductHeadVo.getCgeneralhid());
        headerMap.put("vtrantypecode", finishedProductHeadVo.getVtrantypecode());
        return headerMap;
    }

    /**
     * 更新材料出库单
     *
     * @param headerMap  表头数据
     * @param detailList 明细列表
     * @param loginUser  登录用户
     * @return 更新结果
     */
    private AjaxResult updateFinishedInOrder(HashMap<String, Object> headerMap, List<HashMap<String, Object>> detailList, LoginUser loginUser) {
        HashMap<String, Object> resultMap = new HashMap<>(3);
        resultMap.put("header", headerMap);
        resultMap.put("details", detailList);

        return finishedProductEntryService.updateFinishedProductEntry(resultMap, loginUser, true);
    }

    /**
     * 处理外部接口调用和库存更新
     *
     * @param cgeneralhid 表头主键
     * @param vBillCode   单据编号
     * @param loginUser   登录用户
     * @param detailSize  明细数量
     * @return 结果
     */
    private AjaxResult handleExternalApiAndInventory(String cgeneralhid, String vBillCode, LoginUser loginUser, int detailSize) throws Exception {
        // 调用外部接口
        NccApiResponse apiResponse = nccHttpUtils.post(PRODUCTION_SIGN_API_URL, "[" + cgeneralhid + "]");

        // 校验NCC响应
        DataProcessCommonUtils.validateNccResponse(apiResponse);

        // 更新单据状态
        finishedProductInMapper.updateBillState(cgeneralhid, BillStatusConstant.SIGNED_CODE, loginUser.getUsername(), null);

        // 更新库存管理
        Integer rowCount = inventoryManagerUtils.wmsWarehouseIn(vBillCode, "ProductWareHouseIn");
        if (rowCount != null && detailSize == rowCount) {
            return AjaxResult.success(messageUtil.operateSuccessMessage(Collections.singletonList(vBillCode), DocumentType.FINISHED_PRODUCT_INBOUND.getCode(), "签字"));
        } else {
            finishedProductInMapper.updateBillState(cgeneralhid, BillStatusConstant.WMS_FAILURE_CODE, loginUser.getUsername(), DataProcessUtils.getLocalDate());
            return AjaxResult.error(messageUtil.updateDocumentWmsFailureMessage(DocumentType.FINISHED_PRODUCT_INBOUND.getCode()));
        }
    }

    // ==========================================================
    // 模块名称: NCC删除产成品入库单模块
    // 功能描述: 对NCC删除产成品入库单操作
    // ==========================================================

    /**
     * 删除产成品入库单
     *
     * @param headerId  产成品入库单表头主键
     * @param loginUser 用户信息
     * @param reason    删除原因
     * @return 结果
     */
    @Override
    public AjaxResult finishedProductInDelete(String headerId, LoginUser loginUser, String reason) {
        if (headerId == null) {
            return AjaxResult.error(messageUtil.noSelectOrderMessage(DocumentType.FINISHED_PRODUCT_INBOUND.getCode(), BusinessType.INVALID.getDescription()));
        } else if (headerId.trim().isEmpty()) {
            return AjaxResult.error(messageUtil.noSelectOrderMessage(DocumentType.FINISHED_PRODUCT_INBOUND.getCode(), BusinessType.INVALID.getDescription()));
        }
        // 获取当前单据状态
        HashMap<String, String> billStateMap = finishedProductInMapper.getBillStatus(headerId);
        String billStatus = billStateMap.get("billState");
        String vbillcode = billStateMap.get("vbillcode");

        // 调用消息工具（根据不同的单据状态返回不同的消息）
        AjaxResult ajaxResult = messageUtil.deleteBillMessage(billStatus, DocumentType.FINISHED_PRODUCT_INBOUND.getDescription());
        return ajaxResult.isSuccess() ? handleDeleteBill(headerId, vbillcode, loginUser, reason) : ajaxResult;

    }


    /**
     * 产成品入库单删除
     *
     * @param cgeneralhid 表头主键
     * @param vbillcode   单据编号
     * @param loginUser   用户信息
     * @param reason      删除原因
     * @return 结果
     */
    private AjaxResult handleDeleteBill(String cgeneralhid, String vbillcode, LoginUser loginUser, String reason) {
        try {
            // 调用删除接口
            NccApiResponse nccApiResponse = nccHttpUtils.postNoSaleConfirm(NCC_UPDATE_URL, cgeneralhid, "ic_finprodin_h", "");

            // 校验NCC响应
            DataProcessCommonUtils.validateNccResponse(nccApiResponse);

            finishedProductInMapper.updateBillState(cgeneralhid, BillStatusConstant.DELETED_CODE, loginUser.getUsername(), reason);
            return AjaxResult.success(messageUtil.operateSuccessMessage(Collections.singletonList(vbillcode), DocumentType.FINISHED_PRODUCT_INBOUND.getCode(), BusinessType.INVALID.getDescription()));
        } catch (Exception e) {
            String errorMessage = messageUtil.operateExceptionMessage(DocumentType.FINISHED_PRODUCT_INBOUND.getCode(), e, BusinessType.INVALID.getDescription());
            //            log.error("采购入库单修改异常: ", e);
            throw new RuntimeException(errorMessage, e);
        }
    }


    /**
     * 产成品入库单撤销
     *
     * @param headerId  单据主键
     * @param loginUser 操作用户
     * @return 操作结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult orderBack(String headerId, LoginUser loginUser) {
        HashMap<String, String> billStatusMap = finishedProductInMapper.getBillStatus(headerId);
        String billState = billStatusMap.get("billState");
        String vbillCode = billStatusMap.get("vbillcode");
        AjaxResult ajaxResult = messageUtil.cancelExtractBillMessage(billState, DocumentType.FINISHED_PRODUCT_INBOUND.getDescription());
        return ajaxResult.isSuccess() ? processOrderBack(headerId, loginUser, vbillCode) : ajaxResult;
    }

    private AjaxResult processOrderBack(String headerId, LoginUser loginUser, String vbillCode) {
        // 更新其他入库单表头
        int i = finishedProductInMapper.orderBackHead(headerId, loginUser.getUserId().toString());
        if (i > 0) {
            // 更新其他入库单表体
            int i1 = finishedProductInMapper.orderBackDetails(headerId, loginUser.getUserId().toString());
            if (i1 > 0) {
                return AjaxResult.success(messageUtil.operateSuccessMessage(Collections.singletonList(vbillCode), DocumentType.FINISHED_PRODUCT_INBOUND.getCode(), BusinessType.CANCELED.getDescription()));
            }
        }
        return AjaxResult.error("未知系统错误，请联系系统管理员处理！");
    }

    /**
     * 更新库存
     *
     * @param cgeneralhid 单据主键
     * @param loginUser   登录用户
     * @return 操作结果
     */
    @Override
    public AjaxResult updateInventory(String cgeneralhid, LoginUser loginUser) {
        try {
            // 获取单据明细
            List<FinishedProductBodyVo> details = finishedProductInMapper.selectFinishedProductDetails(cgeneralhid, null);

            // 获取单据表头
            FinishedProductHeadVo finishedProductHeadVo = finishedProductInMapper.selectFinishedInHeaderByBillCode(cgeneralhid);

            // 检查库存是否充足
            inventoryManagerUtils.verifyInventorySign(details, "warehousein", finishedProductHeadVo.getVtrantypecode(), DocumentType.FINISHED_PRODUCT_INBOUND.getCode());

            // 执行入库操作
            Integer rowCount = inventoryManagerUtils.wmsWarehouseIn(finishedProductHeadVo.getVbillcode(), "ProductWareHouseIn");

            // 更新单据状态
            updateBillState(cgeneralhid, loginUser, rowCount, details.size());

            return AjaxResult.success(messageUtil.operateSuccessMessage(Collections.singletonList(finishedProductHeadVo.getVbillcode()), DocumentType.FINISHED_PRODUCT_INBOUND.getCode(), "签字"));
        } catch (InventoryException e) {
//            log.error("库存检查失败: {}", e.getMessage());
            return AjaxResult.error(e.getMessage());
        } catch (Exception e) {
//            log.error("更新库存失败: {}", e.getMessage());
            return AjaxResult.error(e.getMessage());
        }
    }

    /**
     * 检查库存是否充足
     *
     * @param details               明细信息
     * @param finishedProductHeadVo 表头信息
     * @throws InventoryException 库存异常
     */
    private void checkInventory(List<FinishedProductBodyVo> details, FinishedProductHeadVo finishedProductHeadVo) throws InventoryException {
        for (FinishedProductBodyVo detail : details) {
            if (detail.getNshouldnum() < 0) {
                int resultType = inventoryManagerUtils.isEnough(
                        detail.getVbillcode(),
                        finishedProductHeadVo.getVtrantypecode(),
                        detail.getCmaterialvid().getPk(),
                        detail.getVbatchcode(),
                        detail.getNnum(),
                        "2",
                        detail.getCstateid(), "", "");
                if (resultType == InventoryCheck.NO_ENOUGH.ordinal()) {
                    throw new InventoryException(detail.getCmaterialvid().getName() + "库存可用量不足！");
                } else if (resultType == InventoryCheck.NOT_ALLOWED.ordinal()) {
                    throw new InventoryException(detail.getCmaterialvid().getName() + "当前商品不支持在此单据类型下使用！");
                }
            }
        }
    }

    /**
     * 更新单据状态
     *
     * @param cgeneralhid 单据主键
     * @param loginUser   登录用户
     * @param rowCount    入库数量
     * @param detailSize  明细数量
     */
    private void updateBillState(String cgeneralhid, LoginUser loginUser, Integer rowCount, int detailSize) {
        if (rowCount != null && detailSize == rowCount) {
            finishedProductInMapper.updateBillState(cgeneralhid, BillStatusConstant.SIGNED_CODE, loginUser.getUsername(), DataProcessUtils.getLocalDate());
        } else {
            throw new RuntimeException(messageUtil.updateDocumentWmsFailureMessage(DocumentType.FINISHED_PRODUCT_INBOUND.getCode()));
        }
    }
}
